﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TradeSea;
using System.Reflection;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace TradeSea
{
    class ConsoleLine
    {
        public string Line;
        public Color Col;

        public ConsoleLine(string line)
        {
            this.Line = line;
            this.Col = Color.White;
        }

        public ConsoleLine(string line, Color col)
        {
            this.Line = line;
            this.Col = col;
        }
    }

    class DebugConsole
    {
        public MainGame Game;
        private SpriteBatch Batch;
        public TSContentManager Manager;

        private Dictionary<Keys, bool> PressedKeys = new Dictionary<Keys, bool>();

        public Dictionary<CommandAttribute, MethodInfo> Commands = new Dictionary<CommandAttribute, MethodInfo>();

        private List<Keys> NewKeys = new List<Keys>();

        public string currentInput = "";

        public bool ConsoleActive = true;
        public bool StartOfGame = true;


        List<ConsoleLine> OutputHistory = new List<ConsoleLine>();

        public DebugConsole(MainGame game, SpriteBatch batch, TSContentManager manager)
        {
            this.Game = game;
            this.Batch = batch;
            this.Manager = manager;

            TradeSeaShared.Singiltons.OnLog += new TradeSeaShared.Singiltons.LogMethod(Singiltons_OnLog);
            
            LoadAllCommands();
        }

        void Singiltons_OnLog(string type, object message)
        {
            Color col = Color.CornflowerBlue;
            switch (type)
            {
                default:
                    break;
            }
            this.Print(message.ToString(), col);
        }

        public void Print(string message, Color col)
        {
            this.OutputHistory.Add(new ConsoleLine(message, col));
        }

        // mental note: move all this input stuff to another class, also... blah

        char GetFromKey(Keys key)
        {
            switch (key)
            {
                case Keys.A:
                    return 'a';
                case Keys.B:
                    return 'b';
                case Keys.C:
                    return 'c';
                case Keys.D:
                    return 'd';
                case Keys.D0:
                    return '0';
                case Keys.D1:
                    return '1';
                case Keys.D2:
                    return '2';
                case Keys.D3:
                    return '3';
                case Keys.D4:
                    return '4';
                case Keys.D5:
                    return '5';
                case Keys.D6:
                    return '6';
                case Keys.D7:
                    return '7';
                case Keys.D8:
                    return '8';
                case Keys.D9:
                    return '9';
                case Keys.E:
                    return 'e';
                case Keys.F:
                    return 'f';
                case Keys.G:
                    return 'g';
                case Keys.H:
                    return 'h';
                case Keys.I:
                    return 'i';
                case Keys.J:
                    return 'j';
                case Keys.K:
                    return 'k';
                case Keys.L:
                    return 'l';
                case Keys.M:
                    return 'm';
                case Keys.N:
                    return 'n';
                case Keys.O:
                    return 'o';
                case Keys.P:
                    return 'p';
                case Keys.Q:
                    return 'q';
                case Keys.R:
                    return 'r';
                case Keys.S:
                    return 's';
                case Keys.Space:
                    return ' ';
                case Keys.T:
                    return 't';
                case Keys.U:
                    return 'u';
                case Keys.V:
                    return 'v';
                case Keys.W:
                    return 'w';
                case Keys.X:
                    return 'x';
                case Keys.Y:
                    return 'y';
                case Keys.Z:
                    return 'z';
                default:
                    return '-';
            }
        } // yay that's done


        public void Draw()
        {
            if (!this.ConsoleActive) return;

            Manager.FillRectange(this.Batch, new Rectangle(10, 10, Game.Window.ClientBounds.Width - 20, Game.Window.ClientBounds.Height - 20),
                new Color(40, 40, 40, 255));

            int i = 0;

            foreach (ConsoleLine item in this.OutputHistory)
            {
                this.Batch.DrawString(this.Manager.ConsoleFont, item.Line, new Vector2(15, i * 20 + 20), item.Col);
                i++;
            }

            string input = "> " + currentInput;
            if (DateTime.Now.Millisecond % 75 == 0)
            {
                input += "|";
            }

            if (StartOfGame == true)
            {
                this.Batch.DrawString(this.Manager.ConsoleFont, "Welcome to Tradesea. The sailing merchant simulator", new Vector2(15, i * 20 + 20), Color.White);
                this.Batch.DrawString(this.Manager.ConsoleFont, "Press F12 to begin or type a command shown above.", new Vector2(15, (i +1)* 20 + 20), Color.White);
            }

            this.Batch.DrawString(this.Manager.ConsoleFont, input, new Vector2(20, Game.Window.ClientBounds.Height - 40), Color.LightGray);
        }

        public void Update()
        {
            KeyboardState state = Keyboard.GetState();

            List<Keys> pressedKeys = new List<Keys>(state.GetPressedKeys());

            NewKeys.Clear();

            var keys = PressedKeys.Keys;

            for (int q = 0; q < keys.Count; q++)
            {
                if (!pressedKeys.Contains(keys.ElementAt<Keys>(q)))
                {
                    PressedKeys[keys.ElementAt<Keys>(q)] = false;
                }
            }

            foreach (Keys item in pressedKeys)
            {
                if (PressedKeys.ContainsKey(item) && PressedKeys[item])
                {
                    continue;
                }
                else
                {
                    if (!PressedKeys.ContainsKey(item))
                    {
                        PressedKeys.Add(item, true);
                    }
                    else
                    {
                        PressedKeys[item] = true;
                    }

                    NewKeys.Add(item);
                }
            }

            if (NewKeys.Contains(Keys.F12))
            {
                if (ConsoleActive == false)
                {
                    ConsoleActive = true;
                    currentInput = "";
                    int i = 1;
                    foreach (CommandAttribute item in this.Commands.Keys)
                    {
                        this.Print(i.ToString() + ")" + "  " + item.cmdName, Color.Green);
                        i++;
                    }
                }
                else
                {
                    ConsoleActive = false;
                    StartOfGame = false;
                    this.OutputHistory.Clear();
                }
            }

            foreach (Keys item in NewKeys)
            {
                if (GetFromKey(item) != '-')
                {
                    currentInput += GetFromKey(item);
                }

                if (item == Keys.Enter)
                {
                    ProcessCommand(currentInput);
                    currentInput = "";
                }

                if (item == Keys.Back)
                {
                    if (currentInput.Length > 0)
                    {
                        currentInput = currentInput.Substring(0, currentInput.Length - 1);
                    }
                }
            }
        }

        void LoadAllCommands()
        {
            Type commandsClass = Assembly.GetCallingAssembly().GetType("TradeSea.Commands");
            foreach (MethodInfo item in commandsClass.GetMethods(BindingFlags.Public | BindingFlags.Static))
            {
                Commands.Add((CommandAttribute)item.GetCustomAttributes(false)[0], item);
            }
            foreach (CommandAttribute item in this.Commands.Keys)
            {
                this.Print(item.cmdName.PadRight(10) + item.cmdHelp, Color.Green);
            }
        }

        void ProcessCommand(string input)
        {
            StartOfGame = false;
            this.OutputHistory.Clear();
            string[] tokens = input.Split(' ');
            this.OutputHistory.Add(new ConsoleLine(input));

            string[] args = new string[tokens.Length - 1];
            Array.Copy(tokens, 1, args, 0, args.Length);

            foreach (CommandAttribute item in this.Commands.Keys)
            {
                if (item.cmdName == tokens[0])
                {
                    this.Commands[item].Invoke(null, new object[] { this, args });
                    return;
                }
            }
            this.OutputHistory.Add(new ConsoleLine("Command not found", Color.Red));
            int i = 1;
            foreach (CommandAttribute item in this.Commands.Keys)
            {
                this.Print(i.ToString() + ")" + "  " + item.cmdName, Color.Green);
                i++;
            }

        }
    }
}
